package day31.homework;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * TCP客户端程序
 * 实现老师信息的录入、发送和接收服务器响应功能
 * 
 * TCP（传输控制协议）是一种面向连接的、可靠的、基于字节流的传输层通信协议
 * 客户端工作流程：
 * 1. 创建Socket并连接到服务器的指定IP地址和端口
 * 2. 通过Socket的输入输出流与服务器进行数据交互
 * 3. 发送数据给服务器
 * 4. 接收服务器的响应
 * 5. 关闭连接
 */
public class Client {
    /**
     * 程序入口点
     * main方法是Java程序的执行起点
     * @param args 命令行参数数组
     * @throws Exception 抛出所有可能的异常
     */
    public static void main(String[] args) throws Exception {
        // 在控制台输出提示信息，表示客户端正在启动
        System.out.println("客户端启动中");
        // 提示用户输入老师信息的格式和结束条件
        System.out.println("请输入老师信息，格式：姓名-年龄-工资，输入quit结束录入");
        
        // 连接到服务器
        // Socket是客户端套接字，用于与服务器建立连接
        // "localhost"表示连接本地计算机，也可以使用IP地址如"127.0.0.1"
        // 8002是服务器监听的端口号，必须与服务器端口一致才能建立连接
        Socket socket = new Socket("localhost", 8002);
        
        // 创建输出流，用于向服务器发送数据
        // ObjectOutputStream用于写入对象流，可以发送Java对象
        // getOutputStream()方法返回Socket的输出流，用于向服务器发送数据
        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
        
        // 创建输入流，用于接收服务器的数据
        // ObjectInputStream用于读取对象流，可以读取Java对象
        // getInputStream()方法返回Socket的输入流，用于从服务器接收数据
        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        
        // 创建标准输入流，用于读取用户输入
        // System.in是标准输入流，默认指向键盘输入
        // InputStreamReader是字节流到字符流的桥梁
        // BufferedReader提供缓冲功能，提高读取效率，并支持按行读取
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
        
        // 输出已连接到服务器的提示信息
        System.out.println("已连接到服务器");
        
        // 存储老师对象的列表
        // ArrayList是动态数组，可以根据需要自动扩容
        // 这里使用了泛型的原始类型，应该使用ArrayList<Teacher>
        ArrayList teachers = new ArrayList();
        
        // 循环读取用户输入
        // 这是一个无限循环，持续读取用户输入直到用户输入"quit"
        while (true) {
            // 提示用户输入老师信息
            System.out.print("请输入老师信息 (格式: 姓名-年龄-工资) 或输入quit结束: ");
            
            // 读取用户输入的一行文本
            // readLine()方法会阻塞当前线程，直到用户输入回车
            String userInput = stdIn.readLine();
            
            // 如果用户输入quit则结束录入
            // equalsIgnoreCase()方法忽略大小写比较字符串
            if ("quit".equalsIgnoreCase(userInput)) {
                // 使用break语句跳出while循环
                break;
            }
            
            // 解析用户输入并创建老师对象
            // 调用parseTeacherInfo方法解析输入字符串
            Teacher teacher = parseTeacherInfo(userInput);
            
            // 判断解析是否成功
            if (teacher != null) {
                // 解析成功，将老师对象添加到列表中
                teachers.add(teacher);
                // 输出已添加老师信息的提示
                System.out.println("已添加老师信息: " + teacher);
            } else {
                // 解析失败，输出错误提示
                System.out.println("输入格式错误，请重新输入");
            }
        }
        
        // 将老师列表发送到服务器
        // writeObject()方法将对象写入输出流
        // teachers是ArrayList对象，包含所有录入的老师信息
        out.writeObject(teachers);
        // 强制将缓冲区的数据发送出去
        out.flush();
        
        // 输出已发送老师信息数量的提示
        System.out.println("已发送" + teachers.size() + "条老师信息到服务器");
        
        // 接收服务器响应
        // readObject()方法从输入流中读取一个对象
        // 由于网络传输的是字节流，需要强制类型转换为String
        String serverResponse = (String) in.readObject();
        // 输出服务器响应信息
        System.out.println("服务器响应: " + serverResponse);
        
        // 关闭所有资源
        // 按照先开后关的原则，最后打开的流最先关闭
        stdIn.close();       // 关闭标准输入流
        out.close();         // 关闭对象输出流
        in.close();          // 关闭对象输入流
        socket.close();      // 关闭套接字连接
        
        // 输出客户端已关闭的提示信息
        System.out.println("客户端已关闭");
    }
    
    /**
     * 解析用户输入的老师信息字符串
     * 将格式为"姓名-年龄-工资"的字符串解析为Teacher对象
     * @param input 用户输入的字符串，格式为 姓名-年龄-工资
     * @return 解析成功的Teacher对象，解析失败返回null
     */
    private static Teacher parseTeacherInfo(String input) {
        // 使用try-catch块处理可能的异常
        // 如果输入格式不正确，可能会抛出NumberFormatException异常
        try {
            // 按照"-"分割字符串
            // split()方法根据指定分隔符将字符串分割为字符串数组
            String[] parts = input.split("-");
            
            // 检查分割后的部分数量
            // 正确的格式应该包含3部分：姓名、年龄、工资
            if (parts.length != 3) {
                // 如果不是3部分，返回null表示解析失败
                return null;
            }
            
            // 提取各部分信息
            // trim()方法去除字符串首尾的空白字符
            String name = parts[0].trim();                    // 获取姓名
            int age = Integer.parseInt(parts[1].trim());      // 将年龄字符串转换为整数
            double salary = Double.parseDouble(parts[2].trim()); // 将工资字符串转换为双精度浮点数
            
            // 创建并返回Teacher对象
            // 使用解析得到的参数调用Teacher类的构造方法
            return new Teacher(name, age, salary);
        } catch (NumberFormatException e) {
            // 捕获数字格式异常，如年龄或工资不是有效数字
            // 返回null表示解析失败
            return null;
        }
    }
}